package com.qingcheng.service.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSON;
import com.qingcheng.dao.BrandMapper;
import com.qingcheng.dao.SpecMapper;
import com.qingcheng.service.goods.SkuSearchService;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.omg.PortableInterceptor.ServerRequestInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author:boy
 * @Date:2019/7/10
 * @description:
 * @ModifiedBy:
 */
@Service(interfaceClass = SkuSearchService.class)
public class SkuSearchServiceImpl implements SkuSearchService {
    @Autowired
    private RestHighLevelClient restHighLevelClient;
    @Autowired
    private RedisTemplate redisTemplate;

    public Map search(Map<String, String> searchMap) {
        SearchRequest searchRequest = new SearchRequest("sku");
        searchRequest.types("doc");
        //设置查询条件
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        //布尔查询条件
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        //匹配查询条件
        MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("name", searchMap.get("keywords"));
        matchQueryBuilder.analyzer("ik_smart");
        boolQueryBuilder.must(matchQueryBuilder);
        //分类过滤条件
        if (searchMap.get("category") != null) {
            TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("categoryName", searchMap.get("category"));
            boolQueryBuilder.filter(termQueryBuilder);
        }
        //品牌过滤条件
        if (searchMap.get("brand") != null) {
            TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("brand", searchMap.get("brand"));
            boolQueryBuilder.filter(termQueryBuilder);
        }
        //规格过滤条件
        for (String key : searchMap.keySet()) {
            if (key.startsWith("spec.")) {
                TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery(key + ".keyword", searchMap.get(key));
                boolQueryBuilder.filter(termQueryBuilder);
            }
        }
        //价格过滤
        if (searchMap.get("price") != null) {
            String[] prices = searchMap.get("price").split("-");
            if (!prices[0].equals("0")) {
                RangeQueryBuilder price = QueryBuilders.rangeQuery("price").gte(prices[0] + "00");
                boolQueryBuilder.filter(price);
            }
            if (!prices[1].equals("*")) {
                RangeQueryBuilder price = QueryBuilders.rangeQuery("price").lte(prices[1] + "00");
                boolQueryBuilder.filter(price);
            }
        }
        //分页查询
        if (searchMap.get("pageNum") == null) {
            searchMap.put("pageNum", "1");
        }
        if (searchMap.get("size") == null) {
            searchMap.put("size", "20");
        }
        Integer pageNum = Integer.parseInt(searchMap.get("pageNum"));
        Integer size = Integer.parseInt(searchMap.get("size"));
        Integer pageIndex=(pageNum-1)*size;
        searchSourceBuilder.from(pageIndex);
        searchSourceBuilder.size(size);
        //高亮显示
        HighlightBuilder highlightBuilder=new HighlightBuilder();
        highlightBuilder.field("name").preTags("<em class='spec_name'>").postTags("</em>");
        searchSourceBuilder.highlighter(highlightBuilder);
        //排序查询
        String sort=searchMap.get("sort");
        String sortOrder = searchMap.get("sortOrder");
        if (!"".equals(sort)){
            searchSourceBuilder.sort(sort, SortOrder.valueOf(sortOrder));
        }
        //封装查询条件
        searchSourceBuilder.query(boolQueryBuilder);
        //分组查询
        TermsAggregationBuilder aggregationBuilder = AggregationBuilders.terms("sku_category").field("categoryName");
        searchSourceBuilder.aggregation(aggregationBuilder);
        //执行查询
        searchRequest.source(searchSourceBuilder);
        Map resultMap = new HashMap();
        try {
            //查询结果
            SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            SearchHits searchHits = search.getHits();
            long totalCount = searchHits.totalHits;
            System.out.println("总计录数：" +totalCount);
            //计算总页数
            Long totalPage=(totalCount%size==0)?(totalCount/size):(totalCount/size+1);
            resultMap.put("totalPage",totalPage);
            //遍历结果集
            SearchHit[] hits = searchHits.getHits();
            List<Map<String, Object>> skuList = new ArrayList<Map<String, Object>>();
            for (SearchHit hit : hits) {
                Map<String, Object> sourceAsMap = hit.getSourceAsMap();
                //高亮字段处理
                Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                Text[] fragments = highlightFields.get("name").fragments();
                StringBuilder sb=new StringBuilder();
                for (Text fragment : fragments) {
                    sb.append(fragment);
                }
                sourceAsMap.put("name",sb.toString());
                skuList.add(sourceAsMap);
            }
            //如果查询结果为空，直接还回
            if (skuList.size() == 0) {
                return new HashMap();
            }
            //查询结果不为空
            resultMap.put("rows", skuList);

            //分组结果
            Aggregations aggregations = search.getAggregations();
            Map<String, Aggregation> aggregationMap = aggregations.asMap();
            Terms terms = (Terms) aggregationMap.get("sku_category");
            List<? extends Terms.Bucket> buckets = terms.getBuckets();
            List<String> categoryList = new ArrayList<String>();
            for (Terms.Bucket bucket : buckets) {
                categoryList.add(bucket.getKeyAsString());
            }
            resultMap.put("categoryList", categoryList);
            //品牌列表
            String categoryName = null;
            if (searchMap.get("category") == null) {
                categoryName = categoryList.get(0);
            } else {
                categoryName = searchMap.get("category");
            }
            if (searchMap.get("brand") == null) {//不包含品牌条件才查询品牌列表
                //List<Map> brandList = brandMapper.findListByCategoryName(categoryName);
                //缓存中取数据
                System.out.println("redis中取数据brandList");
                String brandList = (String) redisTemplate.boundHashOps(categoryName).get("brandList");
                List<Map> list = JSON.parseObject(brandList, List.class);
                resultMap.put("brandList", list);
            }
            //规格列表
            //List<Map> maps = specMapper.findListByCategoryName(categoryName);
            //从redis中取数据
            System.out.println("redis中取数据specList");
            String specList = (String) redisTemplate.boundHashOps(categoryName).get("specList");
            List<Map> maps = JSON.parseObject(specList, List.class);
            for (Map map : maps) {
                String[] options = ((String) map.get("options")).split(",");
                map.put("options", options);
            }
            resultMap.put("specList", maps);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return resultMap;
    }
}
